package org.webdb.core.config;

import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

public class DatabaseConfig implements Map<String, Object> {

    private Map<String, Object> delegate = null;// new LinkedHashMap<String,
                                                // Object>();

    @SuppressWarnings("unchecked")
    public DatabaseConfig(Map<?, ?> value) {
        this.delegate = (Map<String, Object>) value;
    }

    public DatabaseConfig() {
        delegate = new LinkedHashMap<String, Object>();
    }

    @Override
    public void clear() {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean containsKey(Object key) {
        return delegate.containsKey(key);
    }

    @Override
    public boolean containsValue(Object value) {
        return delegate.containsValue(value);
    }

    @Override
    public Set<Entry<String, Object>> entrySet() {
        return Collections.unmodifiableSet(delegate.entrySet());
    }

    @Override
    public Object get(Object key) {
        Object value = delegate.get(key);
        if (value == null)
            throw new UndefinedPropertyException(key.toString());

        return value;
    }

    @SuppressWarnings("unchecked")
    public <T> T getAs(Object key) {
        return (T) get(key);
    }

    public String getName() {
        return getAs("name");
    }

    public String getType() {
        return getAs("type");
    }

    @Override
    public boolean isEmpty() {
        return delegate.isEmpty();
    }

    @Override
    public Set<String> keySet() {
        return Collections.unmodifiableSet(delegate.keySet());
    }

    @SuppressWarnings("unchecked")
    @Override
    public Object put(String key, Object value) {
        if (delegate.containsKey(key))
            throw new RedefinePropertyException(key);
        if (value != null) {
            if (Map.class.isAssignableFrom(value.getClass())) {
                deep((Map<Object, Object>) value);
                return delegate.put(key, new DatabaseConfig((Map<?, ?>) value));
            }
        }
        return delegate.put(key, value);
    }

    @SuppressWarnings("unchecked")
    private void deep(Map<Object, Object> map) {
        for (Object key : new LinkedHashSet<Object>(map.keySet())) {
            Object value = map.get(key);
            if (Map.class.isAssignableFrom(value.getClass())
                    && !DatabaseConfig.class.isAssignableFrom(value.getClass())) {
                deep((Map<Object, Object>) value);
                map.put(key, new DatabaseConfig((Map<?, ?>) value));
            }
        }
    }

    @Override
    public void putAll(Map<? extends String, ? extends Object> m) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Object remove(Object key) {
        throw new UnsupportedOperationException();
    }

    @Override
    public int size() {
        return delegate.size();
    }

    @Override
    public Collection<Object> values() {
        return Collections.unmodifiableCollection(delegate.values());
    }

}
